/*
 * File : i2c.c
 *
 */

#include "stm32f10x.h"

#define I2C_Speed              100000
#define I2C1_SLAVE_ADDRESS7    0xA0

void I2C_SW_Reset(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	I2C_SoftwareResetCmd(I2C1, ENABLE);
	
	/* Configure I2C1 pins: SCL and SDA */
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
	
	I2C_SoftwareResetCmd(I2C1, DISABLE);
	
	/* Configure I2C1 pins: SCL and SDA */
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void I2C_HW_Init(void)
{
	I2C_InitTypeDef  I2C_InitStructure;
	
	/* Disable the Serial Wire Jtag Debug Port SWJ-DP */
	GPIO_PinRemapConfig(GPIO_Remap_I2C1, DISABLE);
	
	/* clock setting */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
	
	/* I2C Reset */
	I2C_SW_Reset();
	
	/* I2C configuration */
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
	
	/* Apply I2C configuration after enabling it */
	I2C_Init(I2C1, &I2C_InitStructure);
	
	/* I2C Peripheral Enable */
	I2C_Cmd(I2C1, ENABLE);
}

#define I2C_FLAG	1
#define I2C_EVENT	2
int I2C_Check(I2C_TypeDef* I2Cx, unsigned long chk, char type)
{
	int i = 1000;
	
	if (type == I2C_FLAG)
	{
		while(I2C_GetFlagStatus(I2Cx, chk))
		{
			i--;
			if (i == 0)
			{
				I2C_HW_Init();
				return -1;
			}
		}
	}
	else
	{
		while(!I2C_CheckEvent(I2Cx, chk))
		{
			i--;
			if (i == 0)
			{
				I2C_HW_Init();
				return -1;
			}
		}
	}
	return 0;
}

int I2C_Read(unsigned char sid, unsigned char reg, unsigned char *buf, unsigned char len)
{
	unsigned char *pbuf;
		
READ:
	pbuf = buf;
	
	/* While the bus is busy */
	if (I2C_Check(I2C1, I2C_FLAG_BUSY, I2C_FLAG) != 0)
		goto READ;
		
	/* Send START condition */
	I2C_GenerateSTART(I2C1, ENABLE);
	
	/* Test on EV5 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_MODE_SELECT, I2C_EVENT) != 0)
		goto READ;
	 
	/* Send slave addr for write */
	I2C_Send7bitAddress(I2C1, sid, I2C_Direction_Transmitter);
	
	/* Test on EV6 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, I2C_EVENT) != 0)
		goto READ;
	
	/* Clear EV6 by setting again the PE bit */
	I2C_Cmd(I2C1, ENABLE);
	
	/* Send register addr to write to */
	I2C_SendData(I2C1, reg);  
	
	/* Test on EV8 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED, I2C_EVENT) != 0)
		goto READ;
	
	/* Send STRAT condition a second time */  
	I2C_GenerateSTART(I2C1, ENABLE);
	
	/* Test on EV5 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_MODE_SELECT, I2C_EVENT) != 0)
		goto READ;
	
	/* Send slave addr for read */
	I2C_Send7bitAddress(I2C1, sid, I2C_Direction_Receiver);
	
	/* Test on EV6 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED, I2C_EVENT) != 0)
		goto READ;
	
	/* While there is data to be read */
	while(len)  
	{
		if(len == 1)
		{
			/* Disable Acknowledgement */
			I2C_AcknowledgeConfig(I2C1, DISABLE);
			
			/* Send STOP Condition */
			I2C_GenerateSTOP(I2C1, ENABLE);
		}
		
		/* Test on EV7 and clear it */
		if (I2C_Check(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED, I2C_EVENT) != 0)
			goto READ;
		else
		{
			/* Read a byte from the EEPROM */
			*pbuf = I2C_ReceiveData(I2C1);
			
			/* Point to the next location where the byte read will be saved */
			pbuf++; 
			
			/* Decrement the read bytes counter */
			len--;        
		}   
	}
	
	I2C_AcknowledgeConfig(I2C1, ENABLE);
	
	return 0;
}

int I2C_Write(unsigned char sid, unsigned char reg, unsigned char *buf, unsigned char len)
{
	unsigned char *pbuf;
	
WRITE:
	pbuf = buf;
	
	/* While the bus is busy */
	if (I2C_Check(I2C1, I2C_FLAG_BUSY, I2C_FLAG) != 0)
		goto WRITE;
	
	/* Send START condition */
	I2C_GenerateSTART(I2C1, ENABLE);
	
	/* Test on EV5 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_MODE_SELECT, I2C_EVENT) != 0)
		goto WRITE;
	
	/* Send slave address for write */
	I2C_Send7bitAddress(I2C1, sid, I2C_Direction_Transmitter);
	
	/* Test on EV6 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, I2C_EVENT) != 0)
		goto WRITE;
	
	/* Send the register address to write to */
	I2C_SendData(I2C1, reg);  
	
	/* Test on EV8 and clear it */
	if (I2C_Check(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED, I2C_EVENT) != 0)
		goto WRITE;
	
	/* While there is data to be written */
	while(len--)  
	{
	  /* Send the current byte */
	  I2C_SendData(I2C1, *pbuf); 
	
	  /* Point to the next byte to be written */
	  pbuf++; 
	
	  /* Test on EV8 and clear it */
	  if (I2C_Check(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED, I2C_EVENT) != 0)
		goto WRITE;
	}
	
	/* Send STOP condition */
	I2C_GenerateSTOP(I2C1, ENABLE);
	
	return 0;
}


